package student;

import java.rmi.RemoteException;
import java.util.Collection;
import java.util.Vector;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.FinderException;
import javax.ejb.RemoveException;
import javax.ejb.SessionContext;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import offer.Offer;
import placementDiary.PlacementDiary;
import placementDiary.PlacementDiaryHome;
import query.Query;
import sector.Sector;
import timetable.Timetable;
import user.User;
import user.UserHome;
import academicSup.AcademicSup;
import city.City;

import company.Company;
import compsup.CompanySup;

import country.Country;
import cv.CV;
import degree.Degree;
import descriptor.CVDescriptor;
import descriptor.CVListDescriptor;
import descriptor.CitiesListDescriptor;
import descriptor.CompaniesListDescriptor;
import descriptor.CompanyDescriptor;
import descriptor.CountriesListDescriptor;
import descriptor.SectorsListDescriptor;
import descriptor.StudentDescriptor;
import descriptor.TimetableDescriptor;
import descriptor.TimetableListDescriptor;
import feedback.Feedback;

/**
 * StudentBean
 * 
 * @author Mathieu MARET, Mamadou TOURE
 * 
 * The StudentBean class implements all the methods that a remote client expect to find
 * when it calls the interface (Student).
 * 
 * Note : 	-It extends the UserBean class.
 * 			-We use @SuppressWarnings("unchecked") to map the persistent schema of the database
 * 			 and to avoid the warning about the collection element type.
 */
@SuppressWarnings("unchecked")
public abstract class StudentBean  implements EntityBean 
{
	InitialContext initialContext;
	UserHome userHome;
	PlacementDiaryHome placementDiaryHome;
	StudentHome studentHome;
	
	// simple attributes
	/** 
	 * getId
	 * 
	 * The getId abstract method returns a integer which indicates user identification number of a user.
	 * 
	 * @return		The user identification number of a user.
	 */
	public abstract int getId();
	
	/** 
	 * setId
	 * 
	 * The setId abstract method sets the user identification number of a user.
	 * 
	 * @param id		The new user identification number that we want to add.
	 */
	public abstract void setId(int id);
	
	/** 
	 * getLogin
	 * 
	 * The getLogin abstract method returns a string which indicates the login name that user have to provide to log into the application.
	 * 
	 * @return		The login name to provide by the user.
	 */
	public String getLogin()
	{
		return getUser().getLogin();
	}
	
	/** 
	 * setLogin
	 * 
	 * The setLogin abstract method sets the login name of a user.
	 * 
	 * @param login		The new login name that we want to add.
	 */
	public void setLogin(String login)
	{
		getUser().setLogin(login);
	}
	
	/** 
	 * getPasswd
	 * 
	 * The getPasswd abstract method returns a string which indicates the password that user have to provide to log into the application.
	 * 
	 * @return		The password to provide by the user.
	 */
	public String getPasswd()
	{
		return getUser().getPasswd();
	}
	
	/** 
	 * setPasswd
	 * 
	 * The setPasswd abstract method sets the password of a user.
	 * 
	 * @param password		The new password that we want to add.
	 */
	public void setPasswd(String password)
	{
		getUser().setPasswd(password);
	}
	
	/** 
	 * getFirstName
	 * 
	 * The getFirstName abstract method returns a string which indicates the firstname of a user.
	 * 
	 * @return		The user's firstname.
	 */
	public String getFirstName(){
		return getUser().getFirstName();
	}
	
	/** 
	 * setFirstName
	 * 
	 * The setFirstName abstract method sets the firstname of a user.
	 * 
	 * @param firstname		The firstname that we want to add.
	 */
	public void setFirstName(String firstname)
	{
		getUser().setFirstName(firstname);
	}
	
	/** 
	 * getName
	 * 
	 * The getName abstract method returns a string which indicates the surname of a user.
	 * 
	 * @return		The user's surname.
	 */
	public String getName()
	{
		return getUser().getName();
	}
	
	/** 
	 * setName
	 * 
	 * The setName abstract method sets the surname of a user.
	 * 
	 * @param surname		The surname that we want to add.
	 */
	public void setName(String surname)
	{
		getUser().setName(surname);
	}
	
	/** 
	 * getMail
	 * 
	 * The getMail abstract method returns a string which indicates the email address of a user.
	 * 
	 * @return		The email address of a user.
	 */
	public String getMail()
	{
		return getUser().getMail();
	}
	
	/** 
	 * setMail
	 * 
	 * The setMail abstract method sets the email address of a user.
	 * 
	 * @param email		The new email address that we want to add.
	 */
	public void setMail(String email)
	{
		getUser().setMail(email);
	}
	
	// Bean attributes
	// relations 1-1
	/** 
	 * getUser
	 * 
	 * The getUser abstract method returns an object of type User which provides the user's details,
	 * (eg. surname, firstname, login, password,......).
	 * 
	 * @return		A user's object.
	 */
	public abstract User getUser();
	
	/** 
	 * setUser
	 * 
	 * The setUser abstract method sets an object of type User.
	 * 
	 * @param user		A new user's object.
	 */
	public abstract void setUser(User user);
	
	/** 
	 * getPlacementDiary
	 * 
	 * The getPlacementDiary abstract method returns an object of type PlacementDiary which provides the student's diary details.
	 * 
	 * @return		A PlacementDiary's object.
	 */
	public abstract PlacementDiary getPlacementDiary();
	
	/** 
	 * setPlacementDiary
	 * 
	 * The setPlacementDiary abstract method setS an object of type PlacementDiary.
	 * 
	 * @param placementDiary		A new PlacementDiary's object.
	 */
	public abstract void setPlacementDiary(PlacementDiary placementDiary);
	
	/** 
	 * getAcademicSupFeedback
	 * 
	 * The getAcademicSupFeedback abstract method returns an object of type Feedback which provides 
	 * the student's academic supervisor feedback.
	 * 
	 * @return		A Feedback's object.
	 */
	public abstract Feedback getAcademicSupFeedback();
	
	/** 
	 * setAcademicSupFeedback
	 * 
	 * The setAcademicSupFeedback abstract method sets an object of type Feedback.
	 * 
	 * @param academicSupFeedback		A new Feedback's object.
	 */
	public abstract void setAcademicSupFeedback(Feedback academicSupFeedback);
	
	/** 
	 * getCompanySupFeedback
	 * 
	 * The getCompanySupFeedback abstract method returns an object of type Feedback which provides 
	 * the student's company supervisor feedback.
	 * 
	 * @return		A Feedback's object.
	 */
	public abstract Feedback getCompanySupFeedback();
	
	/** 
	 * setCompanySupFeedback
	 * 
	 * The setCompanySupFeedback abstract method sets an object of type Feedback.
	 * 
	 * @param companySupFeedback		A new Feedback's object.
	 */
	public abstract void setCompanySupFeedback(Feedback companySupFeedback);
	
	// relation 1-many
	/** 
	 * getCompanySup
	 * 
	 * The getCompanySup abstract method returns an object of type CompanySup which provides the Company Supervisor's details.
	 * 
	 * @return		A CompanySup's object.
	 */
	public abstract CompanySup getCompanySup();
	
	/** 
	 * setCompanySup
	 * 
	 * The setCompanySup abstract method sets an object of type CompanySup.
	 * 
	 * @param companySup		A new CompanySup's object.
	 */
	public abstract void setCompanySup(CompanySup companySup);
	
	/** 
	 * getAcademicSup
	 * 
	 * The getAcademicSup abstract method returns an object of type AcademicSup which provides the Academic Supervisor's details.
	 * 
	 * @return		A AcademicSup's object.
	 */
	public abstract AcademicSup getAcademicSup();
	
	/** 
	 * setAcademicSup
	 * 
	 * The setAcademicSup abstract method sets an object of type AcademicSup.
	 * 
	 * @param academicSup		A new AcademicSup's object.
	 */
	public abstract void setAcademicSup(AcademicSup academicSup);
	
	/** 
	 * getCVs
	 * 
	 * The getCVs abstract method returns a collection of type CV which provides the CV's details.
	 * 
	 * @return		A CVs' collection.
	 */
	public abstract Collection getCVs();
	
	/** 
	 * setCVs
	 * 
	 * The setCVs abstract method sets a collection of a student's CV.
	 * 
	 * @param CVs		A new collection of a student's CV.
	 */
	public abstract void setCVs(Collection CVs);
	
	/** 
	 * getCompaniesPref
	 * 
	 * The getCompaniesPref abstract method returns a collection of a student's favourite companies.
	 * 
	 * @return		A collection of Company objects, favourite companies of a student.
	 */
	public abstract Collection<Company> getCompaniesPref();
	/** 
	 * setCompaniesPref
	 * 
	 * The setCVs abstract method sets a collection of a student's favourite companies.
	 * 
	 * @param companiesPref		A new collection of Company objects, favourite companies of a student.
	 */
	public abstract void setCompaniesPref(Collection<Company> companiesPref);
	
	public abstract Collection<Sector> getSectorsPref();
	public abstract void setSectorsPref(Collection<Sector> sectorsPref);
	
	public abstract Collection<City> getCitiesPref();
	public abstract void setCitiesPref(Collection<City> citiesPref);
	
	public abstract Collection<Country> getCountriesPref();
	public abstract void setCountriesPref(Collection<Country> countriesPref);
	
	/** 
	 * getDegree
	 * 
	 * The getDegree abstract method returns an object of type Degree which provides the Degree's details.
	 * 
	 * @return		A Degree's object.
	 */
	public abstract Degree getDegree();
	
	/** 
	 * setDegree
	 * 
	 * The setDegree abstract method sets an object of type Degree.
	 * 
	 * @param degree		A new Degree's object.
	 */
	public abstract void setDegree(Degree degree);
	
	/** 
	 * getQueries
	 * 
	 * The getQueries abstract method returns a collection of a student's queries.
	 * 
	 * @return		A collection of a student's queries.
	 */
	public abstract Collection getQueries();
	
	/** 
	 * setQueries
	 * 
	 * The setQueries abstract method sets a collection of a student's queries.
	 * 
	 * @param queries		A new collection of a student's queries.
	 */
	public abstract void setQueries(Collection queries);
	
	/** 
	 * getOffers
	 * 
	 * The getOffers abstract method returns a collection of a student's offers.
	 * 
	 * @return		A collection of a student's offers.
	 */
	public abstract Collection getOffers();
	
	/** 
	 * setOffers
	 * 
	 * The setOffers abstract method sets a collection of a student's offers.
	 * 
	 * @param offers		A new collection of a student's offers.
	 */
	public abstract void setOffers(Collection offers);
	
	public abstract Collection<Timetable>  getTimetables();
	public abstract void setTimetables(Collection<Timetable> Timetable);
	
	/** 
	 * ejbCreate
	 * 
	 * The ejbCreate method defines the operations to follow to create an EJB.
	 * This method refers to the method create in the remote interface.
	 * 
	 * @param firstName			Student's firstname.
	 * @param name				Student's surname.
	 * @param login				Student's login name.
	 * @param passwd			Student's password.
	 * @param mail				Student's email address.
	 * @param degree			Student's degree.
	 * @param companySup		Student's supervisor in company.
	 * @param academicSup		Student's academic supervisor.
	 * 
	 * @return 					Return's values is always null.
	 */
	public String ejbCreate(String firstName,String name, String login,String passwd,String email,Degree degree) throws CreateException
	{

		try 
		{
			initialContext = new InitialContext();
			userHome = (UserHome)initialContext.lookup("java:comp/env/ejb/User");
			studentHome = (StudentHome)initialContext.lookup("MyStudent_L");
			placementDiaryHome = (PlacementDiaryHome)initialContext.lookup("MyPlacementDiary_L");
		} 
		catch (NamingException e) {
			e.printStackTrace();
		}
		User u = null;
		u = userHome.create(firstName, name, login, passwd, email);
		u.setType(User.STUDENT);
		setId(u.getId());
		
		return null;
	}

	/** 
	 * ejbPostCreate
	 * 
	 * The ejbPostCreate method defines the operations to follow after creating an EJB.
	 * 
	 * @param firstName			Student's firstname.
	 * @param name				Student's surname.
	 * @param login				Student's login name.
	 * @param passwd			Student's password.
	 * @param mail				Student's email address.
	 * @param degree			Student's degree.
	 * @param companySup		Student's supervisor in company.
	 * @param academicSup		Student's academic supervisor.
	 * 
	 */
	public void ejbPostCreate(String firstName,String name, String login,String passwd,String email,Degree degree)
	{
		User u = null;
		Student s = null;
		try 
		{
			u = userHome.findByPrimaryKey(getId());
			s = studentHome.findByPrimaryKey(getId());
		} 
		catch (FinderException e) 
		{
			e.printStackTrace();
		}
		setUser(u);
		setDegree(degree);
		setCVs(new Vector<CV>());
		setQueries(new Vector<Query>());
		setOffers(new Vector<Offer>());
		setCompanySup(null);
		setAcademicSup(null);
		setCompaniesPref(new Vector<Company>());
		setSectorsPref(new Vector<Sector>());
		setCitiesPref(new Vector<City>());
		setCountriesPref(new Vector<Country>());
		setCompanySupFeedback(null);
		setAcademicSupFeedback(null);
		PlacementDiary placementDiary = null;
		try 
		{
			placementDiary = placementDiaryHome.create(s);
		} 
		catch (CreateException e) {e.printStackTrace();}
		setPlacementDiary(placementDiary);
		setTimetables(new Vector<Timetable>());
		
	}
	
	/** 
	 * ejbRemove
	 * 
	 * The ejbRemove method defines the operations to follow to delete an EJB.
	 *
	 */
	public void ejbRemove() throws EJBException, RemoteException, RemoveException 
	{
		int id = getId();
		User u = null;
		try 
		{
			u = userHome.findByPrimaryKey(id);
		} 
		catch (FinderException e) 
		{
			e.printStackTrace();
		}
		try 
		{
			u.remove();
		} 
		catch (RemoveException e) 
		{
			e.printStackTrace();
		}
	}
	
	/** 
	 * getDescriptor
	 * 
	 * The getDescriptor method provides a Java object instead of a bean object. Hence, the object is directly accessible from a servlet or a JSP. 
	 * 
	 * @param getId()					The ID of the student
	 * @param getFirstName()			The student's firstname
	 * @param getName()					The student's surname
	 * @param getLogin()				The student's login
	 * @param getPasswd()				The student's password
	 * @param getMail()					The student's email address
	 * @param User.STUDENT				The student's integer type (=1)
	 * @param getDegree()				The student's degree object
	 * @param getCompanySup()			The student's company supervisor object
	 * @param getAcademicSup()			The student's academic supervisor object
	 * @param getPlacementDiary()		The student's placement diary object
	 * @param getAcademicSupFeedback()	The student's academic supervisor feedback object
	 * @param getCompanySupFeedback()	The student's company supervisor feedback object
	 * @param getCVs())					The student's CV collection object
	 * 
	 * @return 							A Student Descriptor's object.
	 */
	public StudentDescriptor getDescriptor()
	{
		
		int degreeid = -1;
		int companySupid = -1;
		int academicSupid = -1;
		int academicSupFeedbackid = -1;
		int companySupFeedbackid = -1;
		if(getDegree() != null)
			degreeid = getDegree().getId();
		if(getCompanySup() != null)
			companySupid = getCompanySup().getId();
		if(getAcademicSup() != null)
			academicSupid = getAcademicSup().getId();
		if(getAcademicSupFeedback() != null)
			academicSupFeedbackid = getAcademicSupFeedback().getId();
		if(getCompanySupFeedback() != null)
			companySupFeedbackid = getAcademicSupFeedback().getId();
		return new StudentDescriptor(getId(),getFirstName(),getName(),getLogin(),getPasswd(),getMail(),User.STUDENT,degreeid,companySupid,academicSupid,getPlacementDiary().getId(),academicSupFeedbackid,companySupFeedbackid,getCVDescriptor(),getTimetableListDescriptor(),getCompaniesListDescriptor(),getSectorsListDescriptor(),getCitiesListDescriptor(),getCountriesListDescriptor());
	}
	
	public CVListDescriptor getCVDescriptor(){
		Collection<CV> cvColl = getCVs();
		CVListDescriptor desc = new CVListDescriptor();
		for(CV cv : cvColl){
			desc.addCVDescriptor(new CVDescriptor(cv.getId(),cv.getFileName(),cv.getFilelocation(),cv.getPublishAuth(),-1));
		}
		return desc;
	}
	
	public TimetableListDescriptor getTimetableListDescriptor()
	{
		Collection<Timetable> tbColl = getTimetables();
		TimetableListDescriptor desc = new TimetableListDescriptor();
		for(Timetable tb : tbColl){
			desc.addTimetableDescriptor(new TimetableDescriptor(tb.getId(),tb.getName(),tb.getDay(), tb.getMonth(),tb.getYear(),tb.getHour(),tb.getMinute(),getId(), tb.getRecruiterName(), tb.getOfferName()));
		}
		return desc;
	}
	
	public CompaniesListDescriptor getCompaniesListDescriptor()
	{
		Collection<Company> compColl = getCompaniesPref();
		CompaniesListDescriptor desc = new CompaniesListDescriptor();
		for(Company comp : compColl){
			desc.addCompanyDescriptor(comp.getSimpleDescriptor());
		}
		return desc;
	}
	
	public SectorsListDescriptor getSectorsListDescriptor()
	{
		Collection<Sector> secColl = getSectorsPref();
		SectorsListDescriptor desc = new SectorsListDescriptor();
		for(Sector sec : secColl){
			desc.addSectorDescriptor(sec.getDescriptor());
		}
		return desc;
	}
	
	public CitiesListDescriptor getCitiesListDescriptor()
	{
		Collection<City> cityColl = getCitiesPref();
		CitiesListDescriptor desc = new CitiesListDescriptor();
		for(City city : cityColl){
			desc.addCityDescriptor(city.getDescriptor());
		}
		return desc;
	}
	
	public CountriesListDescriptor getCountriesListDescriptor()
	{
		Collection<Country> countryColl = getCountriesPref();
		CountriesListDescriptor desc = new CountriesListDescriptor();
		for(Country country : countryColl){
			desc.addCountryDescriptor(country.getDescriptor());
		}
		return desc;
	}
	
	public void ejbActivate() throws EJBException, RemoteException {}
	public void ejbPassivate() throws EJBException, RemoteException {}
	public void setSessionContext(SessionContext arg0) throws EJBException, RemoteException {}
	public void ejbLoad() throws EJBException, RemoteException {}
	public void ejbStore() throws EJBException, RemoteException {}
	public void setEntityContext(EntityContext arg0) throws EJBException, RemoteException {}
	public void unsetEntityContext() throws EJBException, RemoteException {}
}
